import React, { useEffect, useRef, useCallback, forwardRef, useImperativeHandle } from "react";
import { PatternInstance } from "../../types/editor";
import tshirtImage from "../../assest/image/ts.jpeg";
import './Canvas.css';

interface CanvasProps {
  patterns: PatternInstance[];
  selectedPatternId: string | null;
  onPatternSelect: (id: string | null) => void;
  onPatternUpdate: (pattern: PatternInstance) => void;
}

export interface CanvasRef {
  getCanvasData: () => {
    dataUrl: string;
    patternData: PatternInstance[];
  };
}

const Canvas = forwardRef<CanvasRef, CanvasProps>((props, ref) => {
  const { patterns, selectedPatternId, onPatternSelect, onPatternUpdate } = props;
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const fabricCanvasRef = useRef<any>(null);
  const [fabricInstance, setFabricInstance] = React.useState<any>(null);

  // Event handlers
  const handleSelectionCreated = useCallback(
    (e: any) => {
      const selected = e.selected?.[0];
      if (selected?.data?.id) {
        onPatternSelect(selected.data.id);
      }
    },
    [onPatternSelect]
  );

  const handleSelectionUpdated = useCallback(
    (e: any) => {
      const selected = e.selected?.[0];
      if (selected?.data?.id) {
        onPatternSelect(selected.data.id);
      }
    },
    [onPatternSelect]
  );

  const handleSelectionCleared = useCallback(() => {
    onPatternSelect(null);
  }, [onPatternSelect]);

  const handleObjectModified = useCallback(
    (e: any) => {
      const obj = e.target;
      if (obj?.data?.id) {
        onPatternUpdate({
          id: obj.data.id,
          patternId: obj.data.patternId,
          x: obj.left!,
          y: obj.top!,
          scaleX: obj.scaleX!,
          scaleY: obj.scaleY!,
          angle: obj.angle!,
          productImageId: obj.data.productImageId
        });
      }
    },
    [onPatternUpdate]
  );

  // Load Fabric.js dynamically on client side
  useEffect(() => {
    if (typeof window === 'undefined') return;

    const loadFabric = async () => {
      try {
        const fabricModule = await import('fabric');
        setFabricInstance(fabricModule.fabric);
      } catch (error) {
        console.error('Failed to load Fabric.js:', error);
      }
    };
    loadFabric();
  }, []);

  // Initialize canvas when fabric is loaded
  useEffect(() => {
    if (!fabricInstance || !canvasRef.current || fabricCanvasRef.current) return;

    const fabricCanvas = new fabricInstance.Canvas("fabric-canvas", {
      width: 400,
      height: 500,
      backgroundColor: "#ffffff",
      selection: true,
      preserveObjectStacking: true,
    });
    
    fabricCanvasRef.current = fabricCanvas;
    
    // Load T-shirt image
    fabricInstance.Image.fromURL(tshirtImage, (img: any) => {
      if (!fabricCanvas) return;
      
      const scale = Math.min(
        fabricCanvas.width! / img.width!,
        fabricCanvas.height! / img.height!
      ) * 0.9;

      img.scale(scale);

      img.set({
        left: (fabricCanvas.width! - img.width! * scale) / 2,
        top: (fabricCanvas.height! - img.height! * scale) / 2,
        selectable: false,
        hasControls: false,
        hoverCursor: 'default',
      });

      (img as any).data = {
        id: "background",
        patternId: tshirtImage,
        isBackground: true,
      };

      fabricCanvas.add(img);
      fabricCanvas.renderAll();
    }, { crossOrigin: 'anonymous' });

    // Add event listeners
    fabricCanvas.on("selection:created", handleSelectionCreated);
    fabricCanvas.on("selection:updated", handleSelectionUpdated);
    fabricCanvas.on("selection:cleared", handleSelectionCleared);
    fabricCanvas.on("object:modified", handleObjectModified);

    return () => {
      if (fabricCanvas) {
        fabricCanvas.dispose();
        fabricCanvasRef.current = null;
      }
    };
  }, [fabricInstance, handleSelectionCreated, handleSelectionUpdated, handleSelectionCleared, handleObjectModified]);

  // Handle pattern changes
  useEffect(() => {
    if (!fabricInstance || !fabricCanvasRef.current) return;

    const canvas = fabricCanvasRef.current;
    
    // Remove all existing patterns except background
    const objects = canvas.getObjects();
    objects.forEach(obj => {
      if (obj.data?.isBackground) return;
      canvas.remove(obj);
    });

    // Add new patterns
    patterns.forEach(pattern => {
      fabricInstance.Image.fromURL(pattern.patternId, (img: any) => {
        img.set({
          left: pattern.x,
          top: pattern.y,
          scaleX: pattern.scaleX,
          scaleY: pattern.scaleY,
          angle: pattern.angle,
          selectable: true,
          hasControls: true,
        });

        (img as any).data = {
          id: pattern.id,
          patternId: pattern.patternId,
          productImageId: pattern.productImageId
        };

        canvas.add(img);
        canvas.renderAll();

        // If this is the selected pattern, make it active
        if (pattern.id === selectedPatternId) {
          canvas.setActiveObject(img);
        }
      }, { crossOrigin: 'anonymous' });
    });
  }, [patterns, selectedPatternId, fabricInstance]);

  // Expose methods to parent component
  useImperativeHandle(ref, () => ({
    getCanvasData: () => {
      const canvas = fabricCanvasRef.current;
      if (!canvas) {
        throw new Error("Canvas not initialized");
      }

      const dataUrl = canvas.toDataURL({
        format: 'png',
        quality: 1,
        multiplier: 2
      });

      return {
        dataUrl,
        patternData: patterns
      };
    }
  }));

  return (
    <div className="canvas-container">
      <canvas 
        id="fabric-canvas" 
        width="400" 
        height="500" 
        ref={canvasRef}
        className="canvas-element"
      />
    </div>
  );
});

Canvas.displayName = "Canvas";

export default Canvas;
 